/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 map_point.h

	$Header: /heroes4/map_point.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( MAP_POINT_H_INCLUDED )
#define MAP__POINT_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <cmath>
#include <functional>

#include "screen_point.h"
#include "streambuf_operators.h"

// ---------------------------------------------------------------
// data structure for isometric map 2-d points
// ---------------------------------------------------------------
struct t_map_point_2d
{
	// Data members
	int row;
	int column;

	// Constructors
	t_map_point_2d();
	t_map_point_2d( int row_arg, int column_arg );

	// Operators
	t_map_point_2d & operator+=( t_map_point_2d const & right );
	t_map_point_2d & operator-=( t_map_point_2d const & right );
	t_map_point_2d & operator*=( int right );
	t_map_point_2d & operator/=( int right );
	t_map_point_2d & operator%=( int right );
	t_map_point_2d & operator<<=( int right );
	t_map_point_2d & operator>>=( int right );
	t_map_point_2d & operator&=( int right );
	t_map_point_2d & operator&=( t_map_point_2d const & right );
	t_map_point_2d & operator|=( int right );
	t_map_point_2d & operator|=( t_map_point_2d const & right );
	t_map_point_2d & operator^=( int right );
	t_map_point_2d & operator^=( t_map_point_2d const & right );
};

// ---------------------------------------------------------------
// inline member functions for t_map_point_2d
// ---------------------------------------------------------------
inline t_map_point_2d::t_map_point_2d()
	:	row( 0 ), column( 0 )
{
}

inline t_map_point_2d::t_map_point_2d( int row_arg, int column_arg )
	:	row( row_arg ), column( column_arg )
{
}

inline t_map_point_2d & t_map_point_2d::operator+=( t_map_point_2d const & right )
{
	row += right.row;
	column += right.column;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator-=( t_map_point_2d const & right )
{
	row -= right.row;
	column -= right.column;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator*=( int right )
{
	row *= right;
	column *= right;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator/=( int right )
{
	row /= right;
	column /= right;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator%=( int right )
{
	row %= right;
	column %= right;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator<<=( int right )
{
	row <<= right;
	column <<= right;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator>>=( int right )
{
	row >>= right;
	column >>= right;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator&=( int right )
{
	row &= right;
	column &= right;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator&=( t_map_point_2d const & right )
{
	row &= right.row;
	column &= right.column;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator|=( int right )
{
	row |= right;
	column |= right;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator|=( t_map_point_2d const & right )
{
	row |= right.row;
	column |= right.column;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator^=( int right )
{
	row ^= right;
	column ^= right;
	return *this;
}

inline t_map_point_2d & t_map_point_2d::operator^=( t_map_point_2d const & right )
{
	row ^= right.row;
	column ^= right.column;
	return *this;
}

// ---------------------------------------------------------------
// inline free functions for t_map_point_2d
// ---------------------------------------------------------------
inline bool operator==( t_map_point_2d const & left, t_map_point_2d const & right )
{
	return left.row == right.row && left.column == right.column;
}

inline bool operator!=( t_map_point_2d const & left, t_map_point_2d const & right )
{
	return !( left == right );
}

inline t_map_point_2d operator-( t_map_point_2d const & arg )
{
	return t_map_point_2d( -arg.row, -arg.column );
}

inline t_map_point_2d operator~( t_map_point_2d const & arg )
{
	return t_map_point_2d( ~arg.row, ~arg.column );
}

inline t_map_point_2d operator+( t_map_point_2d const & left, t_map_point_2d const & right )
{
	t_map_point_2d result( left );
	result += right;
	return result;
}

inline t_map_point_2d operator-( t_map_point_2d const & left, t_map_point_2d const & right )
{
	t_map_point_2d result( left );
	result -= right;
	return result;
}

inline t_map_point_2d operator*( t_map_point_2d const & left, int right )
{
	t_map_point_2d result( left );
	result *= right;
	return result;
}

inline t_map_point_2d operator*( int left, t_map_point_2d const & right )
{
	return right * left;
}

inline t_map_point_2d operator/( t_map_point_2d const & left, int right )
{
	t_map_point_2d result( left );
	result /= right;
	return result;
}

inline t_map_point_2d operator%( t_map_point_2d const & left, int right )
{
	t_map_point_2d result( left );
	result %= right;
	return result;
}

inline t_map_point_2d operator<<( t_map_point_2d const & left, int right )
{
	t_map_point_2d result( left );
	result <<= right;
	return result;
}

inline t_map_point_2d operator>>( t_map_point_2d const & left, int right )
{
	t_map_point_2d result( left );
	result >>= right;
	return result;
}

template < typename t_right >
inline t_map_point_2d operator&( t_map_point_2d const & left, t_right const & right )
{
	t_map_point_2d result( left );
	result &= right;
	return result;
}

template < typename t_right >
inline t_map_point_2d operator|( t_map_point_2d const & left, t_right const & right )
{
	t_map_point_2d result( left );
	result |= right;
	return result;
}

template < typename t_right >
inline t_map_point_2d operator^( t_map_point_2d const & left, t_right const & right )
{
	t_map_point_2d result( left );
	result ^= right;
	return result;
}

inline double distance( t_map_point_2d const & arg )
{
	return sqrt( (double)(arg.row * arg.row + arg.column * arg.column) );
}

inline int distance_squared( t_map_point_2d const & arg )
{
	return (arg.row * arg.row) + (arg.column * arg.column);
}


inline std::streambuf & operator<<( std::streambuf & stream, t_map_point_2d const & point )
{
	put< t_int32 >( stream, point.row );
	put< t_int32 >( stream, point.column );
	return stream;
}

inline std::streambuf & operator>>( std::streambuf & stream, t_map_point_2d & point )
{
	t_map_point_2d result;
	result.row = get< t_int32 >( stream );
	result.column = get< t_int32 >( stream );
	point = result;
	return stream;
}

// ---------------------------------------------------------------
// std::less< t_map_point_2d > specialization.  Enables the use of
// t_map_point_2d with the standard associative containers.
// ---------------------------------------------------------------

inline bool operator < ( t_map_point_2d const & left, t_map_point_2d const & right )
{
	return left.row < right.row || ( !( right.row < left.row ) && left.column < right.column );
}

// ---------------------------------------------------------------
// data structure for 3-d isometric map points
// ---------------------------------------------------------------

struct t_map_point_3d : public t_map_point_2d
{
	// Data members
	int	height;

	// Constructors
	t_map_point_3d();
	t_map_point_3d( t_map_point_2d const & point_2d, int height_arg );
	t_map_point_3d( int row_arg, int column_arg, int height_arg );

	// Operators
	t_map_point_3d & operator+=( t_map_point_3d const & right );
	t_map_point_3d & operator+=( t_map_point_2d const & right );
	t_map_point_3d & operator-=( t_map_point_3d const & right );
	t_map_point_3d & operator-=( t_map_point_2d const & right );
	t_map_point_3d & operator*=( int right );
	t_map_point_3d & operator/=( int right );
	t_map_point_3d & operator<<=( int right );
	t_map_point_3d & operator>>=( int right );
};

inline t_map_point_3d::t_map_point_3d()
	:	height( 0 )
{
}

inline t_map_point_3d::t_map_point_3d( t_map_point_2d const & point_2d, int height_arg )
	:	t_map_point_2d( point_2d ), height( height_arg )
{
}

inline t_map_point_3d::t_map_point_3d( int row_arg, int column_arg, int height_arg )
	:	t_map_point_2d( row_arg, column_arg ), height( height_arg )
{
}

inline t_map_point_3d & t_map_point_3d::operator+=( t_map_point_3d const & right )
{
	t_map_point_2d::operator+=( right );
	height += right.height;
	return *this;
}

inline t_map_point_3d & t_map_point_3d::operator+=( t_map_point_2d const & right )
{
	t_map_point_2d::operator+=( right );
	return *this;
}

inline t_map_point_3d & t_map_point_3d::operator-=( t_map_point_3d const & right )
{
	t_map_point_2d::operator-=( right );
	height -= right.height;
	return *this;
}

inline t_map_point_3d & t_map_point_3d::operator-=( t_map_point_2d const & right )
{
	t_map_point_2d::operator-=( right );
	return *this;
}

inline t_map_point_3d & t_map_point_3d::operator *=( int right )
{
	column *= right;
	row *= right;
	height *= right;
	return *this;
}

inline t_map_point_3d & t_map_point_3d::operator/=( int right )
{
	column /= right;
	row /= right;
	height /= right;
	return *this;
}

inline t_map_point_3d & t_map_point_3d::operator<<=( int right )
{
	column <<= right;
	row <<= right;
	height <<= right;
	return *this;
}

inline t_map_point_3d & t_map_point_3d::operator>>=( int right )
{
	column >>= right;
	row >>= right;
	height >>= right;
	return *this;
}


// ---------------------------------------------------------------
// inline free functions for t_map_point_3d
// ---------------------------------------------------------------

inline bool operator==( t_map_point_3d const & left, t_map_point_3d const & right )
{
	return		static_cast< t_map_point_2d const & >( left ) == static_cast< t_map_point_2d const & >( right )
			&&	left.height == right.height;
}

inline bool operator!=( t_map_point_3d const & left, t_map_point_3d const & right )
{
	return !( left == right );
}

inline t_map_point_3d operator+( t_map_point_3d const & left, t_map_point_3d const & right )
{
	t_map_point_3d result( left );
	result += right;
	return result;
}

inline t_map_point_3d operator+( t_map_point_3d const & left, t_map_point_2d const & right )
{
	t_map_point_3d result( left );
	result += right;
	return result;
}

inline t_map_point_3d operator+( t_map_point_2d const & left, t_map_point_3d const & right )
{
	return right + left;
}

inline t_map_point_3d operator-( t_map_point_3d const & left, t_map_point_3d const & right )
{
	t_map_point_3d result( left );
	result -= right;
	return result;
}

inline t_map_point_3d operator-( t_map_point_3d const & left, t_map_point_2d const & right )
{
	t_map_point_3d result( left );
	result -= right;
	return result;
}

inline t_map_point_3d operator * ( t_map_point_3d const& left, int right )
{
	t_map_point_3d result( left );
	return result *= right;
}

inline t_map_point_3d operator * ( int left, t_map_point_3d const& right )
{
	t_map_point_3d result( right );
	return result *= left;
}

inline t_map_point_3d operator << ( t_map_point_3d const& left, int right )
{
	t_map_point_3d result( left );
	return result <<= right;
}

inline t_map_point_3d operator >> ( t_map_point_3d const& left, int right )
{
	t_map_point_3d result( left );
	return result >>= right;
}

inline t_map_point_3d operator/( t_map_point_3d const& left, int right )
{
	t_map_point_3d result( left );
	return result /= right;
}

inline std::streambuf & operator<<( std::streambuf & stream, t_map_point_3d const & point )
{
	stream << static_cast< t_map_point_2d const & >( point );
	put< t_int32 >( stream, point.height );
	return stream;
}

inline std::streambuf & operator>>( std::streambuf & stream, t_map_point_3d & point )
{
	t_map_point_3d result;
	stream >> static_cast< t_map_point_2d & >( result );
	result.height = get< t_int32 >( stream );
	point = result;
	return stream;
}

// ---------------------------------------------------------------
// std::less< t_map_point_3d > specialization.  Enables the use of
// t_map_point_3d with the standard associative containers.
// ---------------------------------------------------------------

template <>
struct std::less< t_map_point_3d > : public std::binary_function< t_map_point_3d, t_map_point_3d, bool >
{
	inline bool operator()( t_map_point_3d const & left, t_map_point_3d const & right ) const
  {
    return left.height < right.height || ( !( right.height < left.height ) && std::less< t_map_point_2d >()( left, right ) );
  }
};

// ---------------------------------------------------------------
// data structure for 2d isometric map points with level
// ---------------------------------------------------------------
struct t_level_map_point_2d : public t_map_point_2d
{
	// Data members
	int level;

	// Constructors
	t_level_map_point_2d();
	t_level_map_point_2d( t_map_point_2d const & point_2d, int level_arg );
	t_level_map_point_2d( int row_arg, int column_arg, int level_arg );

	// Operators
	t_level_map_point_2d & operator+=( t_level_map_point_2d const & right );
	t_level_map_point_2d & operator+=( t_map_point_2d const & right );
	t_level_map_point_2d & operator-=( t_level_map_point_2d const & right );
	t_level_map_point_2d & operator-=( t_map_point_2d const & right );
};

// ---------------------------------------------------------------
// inline member functions for t_level_map_point_2d
// ---------------------------------------------------------------
inline t_level_map_point_2d::t_level_map_point_2d()
	:	level( 0 )
{
}

inline t_level_map_point_2d::t_level_map_point_2d( t_map_point_2d const & point_2d, int level_arg )
	:	t_map_point_2d( point_2d ), level( level_arg )
{
}

inline t_level_map_point_2d::t_level_map_point_2d( int row_arg, int column_arg, int level_arg )
	:	t_map_point_2d( row_arg, column_arg ), level( level_arg )
{
}

inline t_level_map_point_2d & t_level_map_point_2d::operator+=( t_level_map_point_2d const & right )
{
	t_map_point_2d::operator+=( right );
	level += right.level;
	return *this;
}

inline t_level_map_point_2d & t_level_map_point_2d::operator+=( t_map_point_2d const & right )
{
	t_map_point_2d::operator+=( right );
	return *this;
}

inline t_level_map_point_2d & t_level_map_point_2d::operator-=( t_level_map_point_2d const & right )
{
	t_map_point_2d::operator-=( right );
	level -= right.level;
	return *this;
}

inline t_level_map_point_2d & t_level_map_point_2d::operator-=( t_map_point_2d const & right )
{
	t_map_point_2d::operator-=( right );
	return *this;
}

// ---------------------------------------------------------------
// inline free functions for t_level_map_point_2d
// ---------------------------------------------------------------
inline bool operator==( t_level_map_point_2d const & left, t_level_map_point_2d const & right )
{
	return		static_cast< t_map_point_2d const & >( left ) == static_cast< t_map_point_2d const & >( right )
			&&	left.level == right.level;
}

inline bool operator!=( t_level_map_point_2d const & left, t_level_map_point_2d const & right )
{
	return !( left == right );
}

inline t_level_map_point_2d operator+( t_level_map_point_2d const & left, t_level_map_point_2d const & right )
{
	t_level_map_point_2d result( left );
	result += right;
	return result;
}

inline t_level_map_point_2d operator+( t_level_map_point_2d const & left, t_map_point_2d const & right )
{
	t_level_map_point_2d result( left );
	result += right;
	return result;
}

inline t_level_map_point_2d operator+( t_map_point_2d const & left, t_level_map_point_2d const & right )
{
	return right + left;
}

inline t_level_map_point_2d operator-( t_level_map_point_2d const & left, t_level_map_point_2d const & right )
{
	t_level_map_point_2d result( left );
	result -= right;
	return result;
}

inline t_level_map_point_2d operator-( t_level_map_point_2d const & left, t_map_point_2d const & right )
{
	t_level_map_point_2d result( left );
	result -= right;
	return result;
}

inline std::streambuf & operator<<( std::streambuf & stream, t_level_map_point_2d const & point )
{
	stream << static_cast< t_map_point_2d const & >( point );
	put< t_int32 >( stream, point.level );
	return stream;
}

inline std::streambuf & operator>>( std::streambuf & stream, t_level_map_point_2d & point )
{
	t_level_map_point_2d result;
	stream >> static_cast< t_map_point_2d & >( result );
	result.level = get< t_int32 >( stream );
	point = result;
	return stream;
}

// ---------------------------------------------------------------
// std::less< t_level_map_point_2d > specialization.  Enables the
// use of t_level_map_point_2d with the standard associative
// containers.
// ---------------------------------------------------------------

template <>
struct std::less< t_level_map_point_2d > : public std::binary_function< t_level_map_point_2d, t_level_map_point_2d, bool >
{
	inline bool operator()( t_level_map_point_2d const & left, t_level_map_point_2d const & right ) const
  {
    return left.level < right.level || ( !( right.level < left.level ) && std::less< t_map_point_2d >()( left, right ) );
  }
};

// ---------------------------------------------------------------
// data structure for 3d isometric map points with level
// ---------------------------------------------------------------
struct t_level_map_point_3d : public t_map_point_3d
{
	// Data members
	int	level;

	// Constructors
	t_level_map_point_3d();
	t_level_map_point_3d( t_map_point_3d const & point_3d, int level_arg );
	t_level_map_point_3d( t_level_map_point_2d const & level_point_2d, int height_arg );
	t_level_map_point_3d( t_map_point_2d const & point_2d, int height_arg, int level_arg );
	t_level_map_point_3d( int row_arg, int column_arg, int height_arg, int level_arg );

	// Operators
	operator t_level_map_point_2d() const;

	t_level_map_point_3d & operator+=( t_level_map_point_3d const & right );
	t_level_map_point_3d & operator+=( t_map_point_3d const & right );
	t_level_map_point_3d & operator+=( t_level_map_point_2d const & right );
	t_level_map_point_3d & operator+=( t_map_point_2d const & right );
	t_level_map_point_3d & operator-=( t_level_map_point_3d const & right );
	t_level_map_point_3d & operator-=( t_map_point_3d const & right );
	t_level_map_point_3d & operator-=( t_level_map_point_2d const & right );
	t_level_map_point_3d & operator-=( t_map_point_2d const & right );
};

inline t_level_map_point_3d::t_level_map_point_3d()
	:	level( 0 )
{
}

inline t_level_map_point_3d::t_level_map_point_3d( t_map_point_3d const & point_3d, int level_arg )
	:	t_map_point_3d( point_3d ), level( level_arg )
{
}

inline t_level_map_point_3d::t_level_map_point_3d( t_level_map_point_2d const & level_point_2d, int height_arg )
	:	t_map_point_3d( level_point_2d, height_arg ), level( level_point_2d.level )
{
}

inline t_level_map_point_3d::t_level_map_point_3d( t_map_point_2d const & point_2d, int height_arg, int level_arg )
	:	t_map_point_3d( point_2d, height_arg ), level( level_arg )
{
}

inline t_level_map_point_3d::t_level_map_point_3d( int row_arg, int column_arg, int height_arg, int level_arg )
	:	t_map_point_3d( row_arg, column_arg, height_arg ), level( level_arg )
{
}

inline t_level_map_point_3d::operator t_level_map_point_2d() const
{
	return t_level_map_point_2d( *this, level );
}

inline t_level_map_point_3d & t_level_map_point_3d::operator+=( t_level_map_point_3d const & right )
{
	t_map_point_3d::operator+=( right );
	level += right.level;
	return *this;
}

inline t_level_map_point_3d & t_level_map_point_3d::operator+=( t_map_point_3d const & right )
{
	t_map_point_3d::operator+=( right );
	return *this;
}

inline t_level_map_point_3d & t_level_map_point_3d::operator+=( t_level_map_point_2d const & right )
{
	t_map_point_3d::operator+=( right );
	level += right.level;
	return *this;
}

inline t_level_map_point_3d & t_level_map_point_3d::operator+=( t_map_point_2d const & right )
{
	t_map_point_3d::operator+=( right );
	return *this;
}

inline t_level_map_point_3d & t_level_map_point_3d::operator-=( t_level_map_point_3d const & right )
{
	t_map_point_3d::operator-=( right );
	level += right.level;
	return *this;
}

inline t_level_map_point_3d & t_level_map_point_3d::operator-=( t_map_point_3d const & right )
{
	t_map_point_3d::operator-=( right );
	return *this;
}

inline t_level_map_point_3d & t_level_map_point_3d::operator-=( t_level_map_point_2d const & right )
{
	t_map_point_3d::operator-=( right );
	level += right.level;
	return *this;
}

inline t_level_map_point_3d & t_level_map_point_3d::operator-=( t_map_point_2d const & right )
{
	t_map_point_3d::operator-=( right );
	return *this;
}

// ---------------------------------------------------------------
// inline free functions for t_level_map_point_3d
// ---------------------------------------------------------------

inline bool operator==( t_level_map_point_3d const & left, t_level_map_point_3d const & right )
{
	return		static_cast< t_map_point_3d const & >( left ) == static_cast< t_map_point_3d const & >( right )
			&&	left.level == right.level;
}

inline bool operator!=( t_level_map_point_3d const & left, t_level_map_point_3d const & right )
{
	return !( left == right );
}

inline t_level_map_point_3d operator+( t_level_map_point_3d const & left, t_level_map_point_3d const & right )
{
	t_level_map_point_3d result( left );
	result += right;
	return result;
}

inline t_level_map_point_3d operator+( t_level_map_point_3d const & left, t_map_point_3d const & right )
{
	t_level_map_point_3d result( left );
	result += right;
	return result;
}

inline t_level_map_point_3d operator+( t_map_point_3d const & left, t_level_map_point_3d const & right )
{
	return right + left;
}

inline t_level_map_point_3d operator+( t_level_map_point_3d const & left, t_level_map_point_2d const & right )
{
	t_level_map_point_3d result( left );
	result += right;
	return result;
}

inline t_level_map_point_3d operator+( t_level_map_point_2d const & left, t_level_map_point_3d const & right )
{
	return right + left;
}

inline t_level_map_point_3d operator+( t_level_map_point_3d const & left, t_map_point_2d const & right )
{
	t_level_map_point_3d result( left );
	result += right;
	return result;
}

inline t_level_map_point_3d operator+( t_map_point_2d const & left, t_level_map_point_3d const & right )
{
	return right + left;
}

inline t_level_map_point_3d operator+( t_map_point_3d const & left, t_level_map_point_2d const & right )
{
	t_level_map_point_3d result( left, 0 );
	result += right;
	return result;
}

inline t_level_map_point_3d operator+( t_level_map_point_2d const & left, t_map_point_3d const & right )
{
	return right + left;
}

inline t_level_map_point_3d operator-( t_level_map_point_3d const & left, t_level_map_point_3d const & right )
{
	t_level_map_point_3d result( left );
	result -= right;
	return result;
}

inline t_level_map_point_3d operator-( t_level_map_point_3d const & left, t_map_point_3d const & right )
{
	t_level_map_point_3d result( left );
	result -= right;
	return result;
}

inline t_level_map_point_3d operator-( t_level_map_point_3d const & left, t_level_map_point_2d const & right )
{
	t_level_map_point_3d result( left );
	result -= right;
	return result;
}

inline t_level_map_point_3d operator-( t_level_map_point_3d const & left, t_map_point_2d const & right )
{
	t_level_map_point_3d result( left );
	result -= right;
	return result;
}

inline t_level_map_point_3d operator-( t_map_point_3d const & left, t_level_map_point_2d const & right )
{
	t_level_map_point_3d result( left, 0 );
	result -= right;
	return result;
}

inline t_level_map_point_3d operator-( t_level_map_point_2d const & left, t_map_point_3d const & right )
{
	t_level_map_point_3d result( left, 0 );
	result -= right;
	return result;
}

inline std::streambuf & operator<<( std::streambuf & stream, t_level_map_point_3d const & point )
{
	stream << static_cast< t_map_point_3d const & >( point );
	put< t_int32 >( stream, point.level );
	return stream;
}

inline std::streambuf & operator>>( std::streambuf & stream, t_level_map_point_3d & point )
{
	t_level_map_point_3d result;
	stream >> static_cast< t_map_point_3d & >( result );
	result.level = get< t_int32 >( stream );
	point = result;
	return stream;
}

// ---------------------------------------------------------------
// std::less< t_level_map_point_3d > specialization.  Enables the
// use of t_level_map_point_3d with the standard associative
// containers.
// ---------------------------------------------------------------

template <>
struct std::less< t_level_map_point_3d > : public std::binary_function< t_level_map_point_3d, t_level_map_point_3d, bool >
{
	inline bool operator()( t_level_map_point_3d const & left, t_level_map_point_3d const & right ) const
  {
    return left.level < right.level || ( !( right.level < left.level ) && std::less< t_map_point_3d >()( left, right ) );
  }
};

// -------------------------------------------------------------------------------
// convert from (column, row) isometric map coordinates to screen coordinates.
// "view_size" is the overall screen size of the viewable portion of the map.
// "map_size" is the width & height, in tiles, of the logical isometric map
// "tile_height" is the height, in pixels, of a single tile.
// tile width is always twice tile height.
// -------------------------------------------------------------------------------

inline t_screen_point convert_map_point_to_screen( const t_map_point_2d& map_point, 
												   const int             tile_height,
												   const                 t_screen_point view_size,
												   const int             map_size )
{
	t_screen_point result;
	const int      tile_width = tile_height * 2;

	result.x = (view_size.x + (map_point.column - map_point.row) * tile_width) / 2;
	result.y = (view_size.y + (map_point.column + map_point.row - map_size) * tile_height) / 2;
	return result;
}

inline t_map_point_2d convert_screen_point_to_map( const t_screen_point screen_point,
												   const int            tile_height, 
												   const t_screen_point view_size,
												   const int            map_size )
{
	t_map_point_2d result;
	const int   tile_width = tile_height * 2;
	const int   x_offset = screen_point.x * 2 - view_size.x;
	const int   y_offset = screen_point.y * 4 - view_size.y * 2;
	const int   map_pixel_width = tile_width * map_size;

	result.column = (x_offset + y_offset + map_pixel_width + 1) / (2 * tile_width);
	result.row    = (y_offset - x_offset + map_pixel_width + 2) / (2 * tile_width);
	return result;
}

inline int sign_of( int arg )
{
	if (arg < 0)
		return -1;
	if (arg > 0)
		return 1;
	return 0;
}

inline t_map_point_2d abs( t_map_point_2d point )
{
	point.column = abs( point.column );
	point.row    = abs( point.row );
	return point;
}

inline t_map_point_2d sign_of( t_map_point_2d point )
{
	point.column = sign_of( point.column );
	point.row    = sign_of( point.row );
	return point;
}

inline t_map_point_3d abs( t_map_point_3d point )
{
	point.column = abs( point.column );
	point.row    = abs( point.row );
	point.height = abs( point.height );
	return point;
}

inline t_map_point_3d sign_of( t_map_point_3d point )
{
	point.column = sign_of( point.column );
	point.row    = sign_of( point.row );
	point.height = sign_of( point.height );
	return point;
}

#endif // !defined( MAP_POINT_H_INCLUDED )
